import json

import sys

sys.path.append("../../python-sdk")
from bcos3sdk.transaction_status import TransactionStatus
from client.contractnote import ContractNote
from client.datatype_parser import DatatypeParser
from inspect import signature


from console_utils.cmd_bcos3_rpc import CmdBcos3RPC
from console_utils import console_common
from console_utils.console_common import match_input_params
from bcos3sdk.bcos3client import Bcos3Client


bcos3clent = Bcos3Client();

#错误信息，有待优化结构和错误码
def make_error(code,cmd,msg='',e=None):
  return {"ret": code, "cmd": cmd ,'msg':msg,'exception': f"{e}"}

#用指定的命令寻找rpc方法，调用它，如getBlockByNumber,参数列表要做一下str到具体类型的转换，已经在match_input_params里实现
def call_rpc(bcos3client,cmd,paramlist):
  rpc_func = console_common.getfunction(bcos3client,cmd)
  if (rpc_func == None):
    result = make_error(-1, cmd, f"{cmd} not found in bcos3client")
    return result

  try:
    sig = signature(rpc_func)
    if len(sig.parameters) == 0:
      result =  rpc_func()
    else:
      matched_paramlist = match_input_params(paramlist, CmdBcos3RPC.param_types[cmd])
      #print("matched_paramlist",matched_paramlist)
      result =  rpc_func(*matched_paramlist)
    print(f"rpc_call {cmd}:",result)
  except Exception as  e:
    print("callrpc exception",e)
    result = make_error(-1,cmd,"exception",e)
  return result


# 解析交易返回。待做一下交易数据signature到方法名的转换
def parse_tx_result(abiparser, result, fn_name=None):
    
    status = result['status']
    if not TransactionStatus.isOK(status):
        print("! transaction ERROR", TransactionStatus.get_error_message(status))
    
    output = result['output']
    
    if fn_name is not None:
        output = abiparser.parse_output(fn_name, output)
        result["output_result"] = output
        print(f"Transaction Output >> {output}")
    if "logEntries" in result:
        logs = abiparser.parse_event_logs(result["logEntries"])
        print("transaction receipt events >>")
        n = 1
        for log in logs:
            print(f"{n} ):{log['eventname']} -> {log['eventdata']}")
            n = n + 1
    return result


# 对应命令行式的调用交易，传入合约名，地址，方法名，参数等
def sendtx(tx_client, contractname, address, fn_name, fn_args):
    if address == "last" or address == "latest":
        address = ContractNote.get_last(tx_client.get_full_name(), contractname)
        if address is None:
            sys.exit(
                "can not get last address for [{}],break;".format(contractname)
            )
    print("INFO>> client info: {}".format(tx_client.getinfo()))
    print(
        "INFO >> sendtx {} , address: {}, func: {}, args:{}".format(
            contractname, address, fn_name, fn_args
        )
    )

    abiparser = DatatypeParser(f"{tx_client.config.contract_dir}/{contractname}.abi")
    (contract_abi, args) = abiparser.format_abi_args(fn_name, fn_args)
    #print("sendtx:", args)
    result = tx_client.sendRawTransaction(address, abiparser.contract_abi, fn_name, args)
    # 解析receipt里的log 和 相关的tx ,output
    parse_tx_result(abiparser, result, fn_name)
    

    #print("sendtx result:", result)
    return result


# 传入地址和rawdata，call某个方法
def callraw(tx_client, address, rawdata, abistr=None):
    fn_name = ""
    if abistr is not None:
        abiparser = DatatypeParser();
        abiparser.from_text(abistr);
        fn_abi = abiparser.get_func_abi_by_selector(rawdata)
        fn_name = fn_abi["name"]
        abi = abiparser.contract_abi
    else:
        abi = None
    #print("callraw ", fn_name)
    result = tx_client.call(address, abi, fn_name, '', raw_func_data=rawdata)
    #print("callraw result: ", result)
    return result


# 对应命令行式的调用call，传入合约名，地址，方法名，参数等
def call(tx_client, contractname, address, fn_name, fn_args, rawdata=None):

    if address == "last" or address == "latest":
        address = ContractNote.get_last(tx_client.get_full_name(), contractname)
        if address is None:
            raise Exception(
                "can not get last address for [{}],break;".format(contractname)
            )
    
    abiparser = DatatypeParser(f"{tx_client.config.contract_dir}/{contractname}.abi")
    
    print("INFO>> client info: {}".format(tx_client.getinfo()))
    print(
        "INFO >> call {} , address: {}, func: {}, args:{}".format(
            contractname, address, fn_name, fn_args
        )
    )
    
    (contract_abi, args) = abiparser.format_abi_args(fn_name, fn_args)
    result = tx_client.call(address, abiparser.contract_abi, fn_name, args, raw_func_data=rawdata)
    print("Call Result:", result)
    
    

    return result
